<?php

if (!defined('ADODB_DIR'))
    die();

if (!defined("_ADODB_MYSQLI_LAYER")) {
    define("_ADODB_MYSQLI_LAYER", 1);
    if (!defined("MYSQLI_BINARY_FLAG"))
        define("MYSQLI_BINARY_FLAG", 128);
    if (!defined('MYSQLI_READ_DEFAULT_GROUP'))
        define('MYSQLI_READ_DEFAULT_GROUP', 1);
    global $ADODB_EXTENSION;
    $ADODB_EXTENSION = false;

    class ADODB_mysqli extends ADOConnection {

        var $databaseType = 'mysqli';
        var $dataProvider = 'native';
        var $hasInsertID = true;
        var $hasAffectedRows = true;
        var $metaTablesSQL = "SELECT TABLE_NAME, CASE WHEN TABLE_TYPE = 'VIEW' THEN 'V' ELSE 'T' END FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=SCHEMA()";
        var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`";
        var $fmtTimeStamp = "'Y-m-d H:i:s'";
        var $hasLimit = true;
        var $hasMoveFirst = true;
        var $hasGenID = true;
        var $isoDates = true;
        var $sysDate = 'CURDATE()';
        var $sysTimeStamp = 'NOW()';
        var $hasTransactions = true;
        var $forceNewConnect = false;
        var $poorAffectedRows = true;
        var $clientFlags = 0;
        var $substr = "substring";
        var $port = false;
        var $socket = false;
        var $_bindInputArray = false;
        var $nameQuote = '`';
        var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP, 0));
        var $arrayClass = 'ADORecordSet_array_mysqli';
        var $multiQuery = false;

        function ADODB_mysqli() {
            
        }

        function SetTransactionMode($transaction_mode) {
            $this->_transmode = $transaction_mode;
            if (empty($transaction_mode)) {
                $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
                return;
            }
            if (!stristr($transaction_mode, 'isolation'))
                $transaction_mode = 'ISOLATION LEVEL ' . $transaction_mode;
            $this->Execute("SET SESSION TRANSACTION " . $transaction_mode);
        }

        function _connect($argHostname = NULL, $argUsername = NULL, $argPassword = NULL, $argDatabasename = NULL, $persist = false) {
            if (!extension_loaded("mysqli")) {
                return null;
            }
            $this->_connectionID = @mysqli_init();

            if (is_null($this->_connectionID)) {
                if ($this->debug)
                    ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg());
                return false;
            }
            foreach ($this->optionFlags as $arr) {
                mysqli_options($this->_connectionID, $arr[0], $arr[1]);
            }
            if ($persist && PHP_VERSION > 5.2 && strncmp($argHostname, 'p:', 2) != 0)
                $argHostname = 'p:' . $argHostname;
            $ok = mysqli_real_connect($this->_connectionID, $argHostname, $argUsername, $argPassword, $argDatabasename, $this->port, $this->socket, $this->clientFlags);

            if ($ok) {
                if ($argDatabasename)
                    return $this->SelectDB($argDatabasename);
                return true;
            } else {
                if ($this->debug)
                    ADOConnection::outp("Could't connect : " . $this->ErrorMsg());
                $this->_connectionID = null;
                return false;
            }
        }

        function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) {
            return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true);
        }

        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) {
            $this->forceNewConnect = true;
            return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename);
        }

        function IfNull($field, $ifNull) {
            return " IFNULL($field, $ifNull) ";
        }

        function GetOne($sql, $inputarr = false) {
            global $ADODB_GETONE_EOF;

            $ret = false;
            $rs = $this->Execute($sql, $inputarr);
            if ($rs) {
                if ($rs->EOF)
                    $ret = $ADODB_GETONE_EOF;
                else
                    $ret = reset($rs->fields);
                $rs->Close();
            }
            return $ret;
        }

        function ServerInfo() {
            $arr['description'] = $this->GetOne("select version()");
            $arr['version'] = ADOConnection::_findvers($arr['description']);
            return $arr;
        }

        function BeginTrans() {
            if ($this->transOff)
                return true;
            $this->transCnt += 1;
            mysqli_autocommit($this->_connectionID, false);
            $this->Execute('BEGIN');
            return true;
        }

        function CommitTrans($ok = true) {
            if ($this->transOff)
                return true;
            if (!$ok)
                return $this->RollbackTrans();

            if ($this->transCnt)
                $this->transCnt -= 1;
            $this->Execute('COMMIT');
            mysqli_autocommit($this->_connectionID, true);
            return true;
        }

        function RollbackTrans() {
            if ($this->transOff)
                return true;
            if ($this->transCnt)
                $this->transCnt -= 1;
            $this->Execute('ROLLBACK');
            mysqli_autocommit($this->_connectionID, true);
            return true;
        }

        function RowLock($tables, $where = '', $col = '1 as adodbignore') {
            if ($this->transCnt == 0)
                $this->BeginTrans();
            if ($where)
                $where = ' where ' . $where;
            $rs = $this->Execute("select $col from $tables $where for update");
            return !empty($rs);
        }

        function qstr($s, $magic_quotes = false) {
            if (is_null($s))
                return 'NULL';
            if (!$magic_quotes) {
                if (PHP_VERSION >= 5)
                    return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'";

                if ($this->replaceQuote[0] == '\\')
                    $s = adodb_str_replace(array('\\', "\0"), array('\\\\', "\\\0"), $s);
                return "'" . str_replace("'", $this->replaceQuote, $s) . "'";
            }
            $s = str_replace('\\"', '"', $s);
            return "'$s'";
        }

        function _insertid() {
            $result = @mysqli_insert_id($this->_connectionID);
            if ($result == -1) {
                if ($this->debug)
                    ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg());
            }
            return $result;
        }

        function _affectedrows() {
            $result = @mysqli_affected_rows($this->_connectionID);
            if ($result == -1) {
                if ($this->debug)
                    ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg());
            }
            return $result;
        }

        var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);";
        var $_genSeqSQL = "create table %s (id int not null)";
        var $_genSeqCountSQL = "select count(*) from %s";
        var $_genSeq2SQL = "insert into %s values (%s)";
        var $_dropSeqSQL = "drop table %s";

        function CreateSequence($seqname = 'adodbseq', $startID = 1) {
            if (empty($this->_genSeqSQL))
                return false;
            $u = strtoupper($seqname);

            $ok = $this->Execute(sprintf($this->_genSeqSQL, $seqname));
            if (!$ok)
                return false;
            return $this->Execute(sprintf($this->_genSeq2SQL, $seqname, $startID - 1));
        }

        function GenID($seqname = 'adodbseq', $startID = 1) {
            if (!$this->hasGenID)
                return false;

            $getnext = sprintf($this->_genIDSQL, $seqname);
            $holdtransOK = $this->_transOK;
            $rs = @$this->Execute($getnext);
            if (!$rs) {
                if ($holdtransOK)
                    $this->_transOK = true;
                $u = strtoupper($seqname);
                $this->Execute(sprintf($this->_genSeqSQL, $seqname));
                $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL, $seqname));
                if (!$cnt)
                    $this->Execute(sprintf($this->_genSeq2SQL, $seqname, $startID - 1));
                $rs = $this->Execute($getnext);
            }

            if ($rs) {
                $this->genID = mysqli_insert_id($this->_connectionID);
                $rs->Close();
            } else
                $this->genID = 0;

            return $this->genID;
        }

        function MetaDatabases() {
            $query = "SHOW DATABASES";
            $ret = $this->Execute($query);
            if ($ret && is_object($ret)) {
                $arr = array();
                while (!$ret->EOF) {
                    $db = $ret->Fields('Database');
                    if ($db != 'mysql')
                        $arr[] = $db;
                    $ret->MoveNext();
                }
                return $arr;
            }
            return $ret;
        }

        function MetaIndexes($table, $primary = FALSE, $owner = false) {
            global $ADODB_FETCH_MODE;

            $false = false;
            $save = $ADODB_FETCH_MODE;
            $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
            if ($this->fetchMode !== FALSE) {
                $savem = $this->SetFetchMode(FALSE);
            }
            $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s', $table));
            if (isset($savem)) {
                $this->SetFetchMode($savem);
            }
            $ADODB_FETCH_MODE = $save;

            if (!is_object($rs)) {
                return $false;
            }

            $indexes = array();
            while ($row = $rs->FetchRow()) {
                if ($primary == FALSE AND $row[2] == 'PRIMARY') {
                    continue;
                }

                if (!isset($indexes[$row[2]])) {
                    $indexes[$row[2]] = array(
                        'unique' => ($row[1] == 0),
                        'columns' => array()
                    );
                }

                $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4];
            }
            foreach (array_keys($indexes) as $index) {
                ksort($indexes[$index]['columns']);
            }

            return $indexes;
        }

        function SQLDate($fmt, $col = false) {
            if (!$col)
                $col = $this->sysTimeStamp;
            $s = 'DATE_FORMAT(' . $col . ",'";
            $concat = false;
            $len = strlen($fmt);
            for ($i = 0; $i < $len; $i++) {
                $ch = $fmt[$i];
                switch ($ch) {
                    case 'Y':
                    case 'y':
                        $s .= '%Y';
                        break;
                    case 'Q':
                    case 'q':
                        $s .= "'),Quarter($col)";

                        if ($len > $i + 1)
                            $s .= ",DATE_FORMAT($col,'";
                        else
                            $s .= ",('";
                        $concat = true;
                        break;
                    case 'M':
                        $s .= '%b';
                        break;

                    case 'm':
                        $s .= '%m';
                        break;
                    case 'D':
                    case 'd':
                        $s .= '%d';
                        break;

                    case 'H':
                        $s .= '%H';
                        break;

                    case 'h':
                        $s .= '%I';
                        break;

                    case 'i':
                        $s .= '%i';
                        break;

                    case 's':
                        $s .= '%s';
                        break;

                    case 'a':
                    case 'A':
                        $s .= '%p';
                        break;

                    case 'w':
                        $s .= '%w';
                        break;

                    case 'l':
                        $s .= '%W';
                        break;

                    default:

                        if ($ch == '\\') {
                            $i++;
                            $ch = substr($fmt, $i, 1);
                        }
                        $s .= $ch;
                        break;
                }
            }
            $s.="')";
            if ($concat)
                $s = "CONCAT($s)";
            return $s;
        }

        function Concat() {
            $s = "";
            $arr = func_get_args();
            $s = implode(',', $arr);
            if (strlen($s) > 0)
                return "CONCAT($s)";
            else
                return '';
        }

        function OffsetDate($dayFraction, $date = false) {
            if (!$date)
                $date = $this->sysDate;

            $fraction = $dayFraction * 24 * 3600;
            return $date . ' + INTERVAL ' . $fraction . ' SECOND';
        }

        function MetaProcedures($NamePattern = false, $catalog = null, $schemaPattern = null) {
            global $ADODB_FETCH_MODE;

            $false = false;
            $save = $ADODB_FETCH_MODE;
            $ADODB_FETCH_MODE = ADODB_FETCH_NUM;

            if ($this->fetchMode !== FALSE) {
                $savem = $this->SetFetchMode(FALSE);
            }

            $procedures = array();
            $likepattern = '';
            if ($NamePattern) {
                $likepattern = " LIKE '" . $NamePattern . "'";
            }
            $rs = $this->Execute('SHOW PROCEDURE STATUS' . $likepattern);
            if (is_object($rs)) {
                while ($row = $rs->FetchRow()) {
                    $procedures[$row[1]] = array(
                        'type' => 'PROCEDURE',
                        'catalog' => '',
                        'schema' => '',
                        'remarks' => $row[7],
                    );
                }
            }

            $rs = $this->Execute('SHOW FUNCTION STATUS' . $likepattern);
            if (is_object($rs)) {
                while ($row = $rs->FetchRow()) {
                    $procedures[$row[1]] = array(
                        'type' => 'FUNCTION',
                        'catalog' => '',
                        'schema' => '',
                        'remarks' => $row[7]
                    );
                }
            }
            if (isset($savem)) {
                $this->SetFetchMode($savem);
            }
            $ADODB_FETCH_MODE = $save;


            return $procedures;
        }

        function MetaTables($ttype = false, $showSchema = false, $mask = false) {
            $save = $this->metaTablesSQL;
            if ($showSchema && is_string($showSchema)) {
                $this->metaTablesSQL .= " from $showSchema";
            }

            if ($mask) {
                $mask = $this->qstr($mask);
                $this->metaTablesSQL .= " like $mask";
            }
            $ret = ADOConnection::MetaTables($ttype, $showSchema);

            $this->metaTablesSQL = $save;
            return $ret;
        }

        function MetaForeignKeys($table, $owner = FALSE, $upper = FALSE, $associative = FALSE) {
            global $ADODB_FETCH_MODE;

            if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC)
                $associative = true;

            if (!empty($owner)) {
                $table = "$owner.$table";
            }
            $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table));
            if ($associative) {
                $create_sql = isset($a_create_table["Create Table"]) ? $a_create_table["Create Table"] : $a_create_table["Create View"];
            } else
                $create_sql = $a_create_table[1];

            $matches = array();

            if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches))
                return false;
            $foreign_keys = array();
            $num_keys = count($matches[0]);
            for ($i = 0; $i < $num_keys; $i ++) {
                $my_field = explode('`, `', $matches[1][$i]);
                $ref_table = $matches[2][$i];
                $ref_field = explode('`, `', $matches[3][$i]);

                if ($upper) {
                    $ref_table = strtoupper($ref_table);
                }
                if (!isset($foreign_keys[$ref_table])) {
                    $foreign_keys[$ref_table] = array();
                }
                $num_fields = count($my_field);
                for ($j = 0; $j < $num_fields; $j ++) {
                    if ($associative) {
                        $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j];
                    } else {
                        $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}";
                    }
                }
            }

            return $foreign_keys;
        }

        function MetaColumns($table, $normalize = true) {
            $false = false;
            if (!$this->metaColumnsSQL)
                return $false;

            global $ADODB_FETCH_MODE;
            $save = $ADODB_FETCH_MODE;
            $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
            if ($this->fetchMode !== false)
                $savem = $this->SetFetchMode(false);
            $rs = $this->Execute(sprintf($this->metaColumnsSQL, $table));
            if (isset($savem))
                $this->SetFetchMode($savem);
            $ADODB_FETCH_MODE = $save;
            if (!is_object($rs))
                return $false;

            $retarr = array();
            while (!$rs->EOF) {
                $fld = new ADOFieldObject();
                $fld->name = $rs->fields[0];
                $type = $rs->fields[1];
                $fld->scale = null;
                if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) {
                    $fld->type = $query_array[1];
                    $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
                    $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1;
                } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) {
                    $fld->type = $query_array[1];
                    $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1;
                } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) {
                    $fld->type = $query_array[1];
                    $arr = explode(",", $query_array[2]);
                    $fld->enums = $arr;
                    $zlen = max(array_map("strlen", $arr)) - 2;
                    $fld->max_length = ($zlen > 0) ? $zlen : 1;
                } else {
                    $fld->type = $type;
                    $fld->max_length = -1;
                }
                $fld->not_null = ($rs->fields[2] != 'YES');
                $fld->primary_key = ($rs->fields[3] == 'PRI');
                $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false);
                $fld->binary = (strpos($type, 'blob') !== false);
                $fld->unsigned = (strpos($type, 'unsigned') !== false);
                $fld->zerofill = (strpos($type, 'zerofill') !== false);

                if (!$fld->binary) {
                    $d = $rs->fields[4];
                    if ($d != '' && $d != 'NULL') {
                        $fld->has_default = true;
                        $fld->default_value = $d;
                    } else {
                        $fld->has_default = false;
                    }
                }

                if ($save == ADODB_FETCH_NUM) {
                    $retarr[] = $fld;
                } else {
                    $retarr[strtoupper($fld->name)] = $fld;
                }
                $rs->MoveNext();
            }

            $rs->Close();
            return $retarr;
        }

        function SelectDB($dbName) {
            $this->database = $dbName;
            $this->databaseName = $dbName;

            if ($this->_connectionID) {
                $result = @mysqli_select_db($this->_connectionID, $dbName);
                if (!$result) {
                    ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg());
                }
                return $result;
            }
            return false;
        }

        function SelectLimit($sql, $nrows = -1, $offset = -1, $inputarr = false, $secs = 0) {
            $offsetStr = ($offset >= 0) ? "$offset," : '';
            if ($nrows < 0)
                $nrows = '18446744073709551615';

            if ($secs)
                $rs = $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows", $inputarr);
            else
                $rs = $this->Execute($sql . " LIMIT $offsetStr$nrows", $inputarr);

            return $rs;
        }

        function Prepare($sql) {
            return $sql;
            $stmt = $this->_connectionID->prepare($sql);
            if (!$stmt) {
                echo $this->ErrorMsg();
                return $sql;
            }
            return array($sql, $stmt);
        }

        function _query($sql, $inputarr) {
            global $ADODB_COUNTRECS;
            if (is_array($sql)) {
                $stmt = $sql[1];
                $a = '';
                foreach ($inputarr as $k => $v) {
                    if (is_string($v))
                        $a .= 's';
                    else if (is_integer($v))
                        $a .= 'i';
                    else
                        $a .= 'd';
                }

                $fnarr = array_merge(array($stmt, $a), $inputarr);
                $ret = call_user_func_array('mysqli_stmt_bind_param', $fnarr);
                $ret = mysqli_stmt_execute($stmt);
                return $ret;
            }
            if ($this->multiQuery) {
                $rs = mysqli_multi_query($this->_connectionID, $sql . ';');
                if ($rs) {
                    $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result($this->_connectionID) : @mysqli_use_result($this->_connectionID);
                    return $rs ? $rs : true;
                }
            } else {
                $rs = mysqli_query($this->_connectionID, $sql, $ADODB_COUNTRECS ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);

                if ($rs)
                    return $rs;
            }

            if ($this->debug)
                ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg());

            return false;
        }

        function ErrorMsg() {
            if (empty($this->_connectionID))
                $this->_errorMsg = @mysqli_connect_error();
            else
                $this->_errorMsg = @mysqli_error($this->_connectionID);
            return $this->_errorMsg;
        }

        function ErrorNo() {
            if (empty($this->_connectionID))
                return @mysqli_connect_errno();
            else
                return @mysqli_errno($this->_connectionID);
        }

        function _close() {
            @mysqli_close($this->_connectionID);
            $this->_connectionID = false;
        }

        function CharMax() {
            return 255;
        }

        function TextMax() {
            return 4294967295;
        }

        function GetCharSet() {
            if (!method_exists($this->_connectionID, 'character_set_name'))
                return false;

            $this->charSet = @$this->_connectionID->character_set_name();
            if (!$this->charSet) {
                return false;
            } else {
                return $this->charSet;
            }
        }

        function SetCharSet($charset_name) {
            if (!method_exists($this->_connectionID, 'set_charset'))
                return false;

            if ($this->charSet !== $charset_name) {
                $if = @$this->_connectionID->set_charset($charset_name);
                if ($if == "0" & $this->GetCharSet() == $charset_name) {
                    return true;
                } else
                    return false;
            } else
                return true;
        }

    }

    class ADORecordSet_mysqli extends ADORecordSet {

        var $databaseType = "mysqli";
        var $canSeek = true;

        function ADORecordSet_mysqli($queryID, $mode = false) {
            if ($mode === false) {
                global $ADODB_FETCH_MODE;
                $mode = $ADODB_FETCH_MODE;
            }

            switch ($mode) {
                case ADODB_FETCH_NUM:
                    $this->fetchMode = MYSQLI_NUM;
                    break;
                case ADODB_FETCH_ASSOC:
                    $this->fetchMode = MYSQLI_ASSOC;
                    break;
                case ADODB_FETCH_DEFAULT:
                case ADODB_FETCH_BOTH:
                default:
                    $this->fetchMode = MYSQLI_BOTH;
                    break;
            }
            $this->adodbFetchMode = $mode;
            $this->ADORecordSet($queryID);
        }

        function _initrs() {
            global $ADODB_COUNTRECS;

            $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1;
            $this->_numOfFields = @mysqli_num_fields($this->_queryID);
        }

        function FetchField($fieldOffset = -1) {
            $fieldnr = $fieldOffset;
            if ($fieldOffset != -1) {
                $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr);
            }
            $o = @mysqli_fetch_field($this->_queryID);
            if (!$o)
                return false;
            $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG;
            $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG;
            $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG;
            $o->binary = $o->flags & MYSQLI_BINARY_FLAG;
            $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG;

            return $o;
        }

        function GetRowAssoc($upper = true) {
            if ($this->fetchMode == MYSQLI_ASSOC && !$upper)
                return $this->fields;
            $row = ADORecordSet::GetRowAssoc($upper);
            return $row;
        }

        function Fields($colname) {
            if ($this->fetchMode != MYSQLI_NUM)
                return @$this->fields[$colname];

            if (!$this->bind) {
                $this->bind = array();
                for ($i = 0; $i < $this->_numOfFields; $i++) {
                    $o = $this->FetchField($i);
                    $this->bind[strtoupper($o->name)] = $i;
                }
            }
            return $this->fields[$this->bind[strtoupper($colname)]];
        }

        function _seek($row) {
            if ($this->_numOfRows == 0)
                return false;

            if ($row < 0)
                return false;

            mysqli_data_seek($this->_queryID, $row);
            $this->EOF = false;
            return true;
        }

        function NextRecordSet() {
            global $ADODB_COUNTRECS;

            mysqli_free_result($this->_queryID);
            $this->_queryID = -1;
            if (!mysqli_next_result($this->connection->_connectionID)) {
                return false;
            }
            $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result($this->connection->_connectionID) : @mysqli_use_result($this->connection->_connectionID);
            if (!$this->_queryID) {
                return false;
            }
            $this->_inited = false;
            $this->bind = false;
            $this->_currentRow = -1;
            $this->Init();
            return true;
        }

        function MoveNext() {
            if ($this->EOF)
                return false;
            $this->_currentRow++;
            $this->fields = @mysqli_fetch_array($this->_queryID, $this->fetchMode);

            if (is_array($this->fields))
                return true;
            $this->EOF = true;
            return false;
        }

        function _fetch() {
            $this->fields = mysqli_fetch_array($this->_queryID, $this->fetchMode);
            return is_array($this->fields);
        }

        function _close() {
            while (mysqli_more_results($this->connection->_connectionID)) {
                @mysqli_next_result($this->connection->_connectionID);
            }

            mysqli_free_result($this->_queryID);
            $this->_queryID = false;
        }

        function MetaType($t, $len = -1, $fieldobj = false) {
            if (is_object($t)) {
                $fieldobj = $t;
                $t = $fieldobj->type;
                $len = $fieldobj->max_length;
            }


            $len = -1;
            switch (strtoupper($t)) {
                case 'STRING':
                case 'CHAR':
                case 'VARCHAR':
                case 'TINYBLOB':
                case 'TINYTEXT':
                case 'ENUM':
                case 'SET':

                case MYSQLI_TYPE_TINY_BLOB :
                case MYSQLI_TYPE_STRING :
                case MYSQLI_TYPE_ENUM :
                case MYSQLI_TYPE_SET :
                case 253 :
                    if ($len <= $this->blobSize)
                        return 'C';

                case 'TEXT':
                case 'LONGTEXT':
                case 'MEDIUMTEXT':
                    return 'X';
                case 'IMAGE':
                case 'LONGBLOB':
                case 'BLOB':
                case 'MEDIUMBLOB':

                case MYSQLI_TYPE_BLOB :
                case MYSQLI_TYPE_LONG_BLOB :
                case MYSQLI_TYPE_MEDIUM_BLOB :

                    return !empty($fieldobj->binary) ? 'B' : 'X';
                case 'YEAR':
                case 'DATE':
                case MYSQLI_TYPE_DATE :
                case MYSQLI_TYPE_YEAR :

                    return 'D';

                case 'TIME':
                case 'DATETIME':
                case 'TIMESTAMP':

                case MYSQLI_TYPE_DATETIME :
                case MYSQLI_TYPE_NEWDATE :
                case MYSQLI_TYPE_TIME :
                case MYSQLI_TYPE_TIMESTAMP :

                    return 'T';

                case 'INT':
                case 'INTEGER':
                case 'BIGINT':
                case 'TINYINT':
                case 'MEDIUMINT':
                case 'SMALLINT':

                case MYSQLI_TYPE_INT24 :
                case MYSQLI_TYPE_LONG :
                case MYSQLI_TYPE_LONGLONG :
                case MYSQLI_TYPE_SHORT :
                case MYSQLI_TYPE_TINY :

                    if (!empty($fieldobj->primary_key))
                        return 'R';

                    return 'I';
                case 'FLOAT':
                case 'DOUBLE':
                case 'DECIMAL':
                case 'DEC':
                case 'FIXED':
                default:
                    return 'N';
            }
        }

    }

}

class ADORecordSet_array_mysqli extends ADORecordSet_array {

    function ADORecordSet_array_mysqli($id = -1, $mode = false) {
        $this->ADORecordSet_array($id, $mode);
    }

    function MetaType($t, $len = -1, $fieldobj = false) {
        if (is_object($t)) {
            $fieldobj = $t;
            $t = $fieldobj->type;
            $len = $fieldobj->max_length;
        }


        $len = -1;
        switch (strtoupper($t)) {
            case 'STRING':
            case 'CHAR':
            case 'VARCHAR':
            case 'TINYBLOB':
            case 'TINYTEXT':
            case 'ENUM':
            case 'SET':

            case MYSQLI_TYPE_TINY_BLOB :
            #case MYSQLI_TYPE_CHAR :
            case MYSQLI_TYPE_STRING :
            case MYSQLI_TYPE_ENUM :
            case MYSQLI_TYPE_SET :
            case 253 :
                if ($len <= $this->blobSize)
                    return 'C';

            case 'TEXT':
            case 'LONGTEXT':
            case 'MEDIUMTEXT':
                return 'X';
            case 'IMAGE':
            case 'LONGBLOB':
            case 'BLOB':
            case 'MEDIUMBLOB':

            case MYSQLI_TYPE_BLOB :
            case MYSQLI_TYPE_LONG_BLOB :
            case MYSQLI_TYPE_MEDIUM_BLOB :

                return !empty($fieldobj->binary) ? 'B' : 'X';
            case 'YEAR':
            case 'DATE':
            case MYSQLI_TYPE_DATE :
            case MYSQLI_TYPE_YEAR :

                return 'D';

            case 'TIME':
            case 'DATETIME':
            case 'TIMESTAMP':

            case MYSQLI_TYPE_DATETIME :
            case MYSQLI_TYPE_NEWDATE :
            case MYSQLI_TYPE_TIME :
            case MYSQLI_TYPE_TIMESTAMP :

                return 'T';

            case 'INT':
            case 'INTEGER':
            case 'BIGINT':
            case 'TINYINT':
            case 'MEDIUMINT':
            case 'SMALLINT':

            case MYSQLI_TYPE_INT24 :
            case MYSQLI_TYPE_LONG :
            case MYSQLI_TYPE_LONGLONG :
            case MYSQLI_TYPE_SHORT :
            case MYSQLI_TYPE_TINY :

                if (!empty($fieldobj->primary_key))
                    return 'R';

                return 'I';
            case 'FLOAT':
            case 'DOUBLE':
            case 'DECIMAL':
            case 'DEC':
            case 'FIXED':
            default:
                return 'N';
        }
    }

}

?>